#include "LogicSystem.h"
#include "HttpConnection.h"
#include "VerifyGrpcClient.h"
#include "StatusGrpcClient.h"
#include "RedisManager.h"
#include "MysqlManager.h"


// 注册http的get请求
void LogicSystem::registerGet(std::string url, HttpHandler handler)
{
	m_getHandlers.insert({ url, handler });
}

// 注册http的post请求
void LogicSystem::registerPost(std::string url, HttpHandler handler)
{
	m_postHandlers.insert({ url, handler });
}

// 处理http的get请求
bool LogicSystem::handleGet(std::string path, std::shared_ptr<HttpConnection> con)
{
	auto it = m_getHandlers.find(path);
	if (it == m_getHandlers.end()) {
		return false;
	}

	// 调用处理http的get请求的回调函数
	it->second(con);

	return true;
}

// 处理http的post请求
bool LogicSystem::handlePost(std::string path, std::shared_ptr<HttpConnection> con)
{
	auto it = m_postHandlers.find(path);
	if (it == m_postHandlers.end()) {
		return false;
	}

	// 调用处理http的get请求的回调函数
	it->second(con);

	return true;
}

// 测试GET请求
void LogicSystem::handleGetTest(std::shared_ptr<HttpConnection> connection)
{
	boost::beast::ostream(connection->m_response.body()) << "receive getTest req......";
	int i = 0;
	for (const auto& elem : connection->m_getParams) {
		i++;
		boost::beast::ostream(connection->m_response.body()) << "param" << i << " key is " << elem.first;
		boost::beast::ostream(connection->m_response.body()) << ", " << " value is " << elem.second << std::endl;
	}
}

void LogicSystem::handlePostVerifyCode(std::shared_ptr<HttpConnection> connection)
{
	auto bodyStr = boost::beast::buffers_to_string(connection->m_request.body().data());
	std::cout << "receive body is " << bodyStr << std::endl;
	connection->m_response.set(boost::beast::http::field::content_type, "text/json");
	Json::Value root;
	Json::Reader reader;
	Json::Value src_root;
	bool parse_success = reader.parse(bodyStr, src_root);
	if (!parse_success) {
		std::cout << "Failed to parse JSON data!" << std::endl;
		root["error"] = ErrorCodes::Error_Json;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	if (!src_root.isMember("email")) {
		std::cout << "Failed to parse JSON data!" << std::endl;
		root["error"] = ErrorCodes::Error_Json;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	auto email = src_root["email"].asString();
	message::GetVerifyRsp rsp = VerifyGrpcClient::getInstance()->GetVerifyCode(email);
	std::cout << "email is " << email << std::endl;
	root["error"] = rsp.error();
	root["email"] = src_root["email"];
	std::string jsonstr = root.toStyledString();
	boost::beast::ostream(connection->m_response.body()) << jsonstr;
}

// 处理用户注册
void LogicSystem::handleUserRegister(std::shared_ptr<HttpConnection> connection)
{
	auto body_str = boost::beast::buffers_to_string(connection->m_request.body().data());
	std::cout << "receive body is " << body_str << std::endl;
	connection->m_response.set(boost::beast::http::field::content_type, "text/json");
	Json::Value root;
	Json::Reader reader;
	Json::Value src_root;
	bool parse_success = reader.parse(body_str, src_root);
	if (!parse_success) {
		std::cout << "Failed to parse JSON data!" << std::endl;
		root["error"] = ErrorCodes::Error_Json;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	auto email = src_root["email"].asString();
	auto name = src_root["user"].asString();
	auto pwd = src_root["passwd"].asString();
	auto confirm = src_root["confirm"].asString();
	auto icon = src_root["icon"].asString();

	if (pwd != confirm) {
		std::cout << "password err " << std::endl;
		root["error"] = ErrorCodes::PasswdErr;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	// 先查找redis中email对应的验证码是否合理
	// 验证码是否过期
	std::string  verify_code;
	bool b_get_verify = RedisManager::getInstance()->get(CODEPREFIX + src_root["email"].asString(), verify_code);
	if (!b_get_verify) {
		std::cout << " get verify code expired" << std::endl;
		root["error"] = ErrorCodes::VerifyExpired;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	// 验证码是否合理
	if (verify_code != src_root["verifycode"].asString()) {
		std::cout << " verify code error" << std::endl;
		root["error"] = ErrorCodes::VerifyCodeErr;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	// 查找数据库判断用户是否存在，若不存在，则注册新用户
	int uid = MysqlManager::getInstance()->regUser(name, email, pwd, icon);
	if (uid == 0 || uid == -1) {
		std::cout << " user or email exist" << std::endl;
		root["error"] = ErrorCodes::UserExist;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	root["error"] = 0;
	root["uid"] = uid;
	root["email"] = email;
	root["user"] = name;
	root["passwd"] = pwd;
	root["confirm"] = confirm;
	root["icon"] = icon;
	root["verifycode"] = src_root["verifycode"].asString();

	std::string jsonstr = root.toStyledString();
	boost::beast::ostream(connection->m_response.body()) << jsonstr;
}

// 处理用户重置密码
void LogicSystem::handleResetPwd(std::shared_ptr<HttpConnection> connection)
{
	auto body_str = boost::beast::buffers_to_string(connection->m_request.body().data());
	std::cout << "receive body is " << body_str << std::endl;
	connection->m_response.set(boost::beast::http::field::content_type, "text/json");
	Json::Value root;
	Json::Reader reader;
	Json::Value src_root;
	bool parse_success = reader.parse(body_str, src_root);
	if (!parse_success) {
		std::cout << "Failed to parse JSON data!" << std::endl;
		root["error"] = ErrorCodes::Error_Json;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	auto email = src_root["email"].asString();
	auto name = src_root["user"].asString();
	auto pwd = src_root["passwd"].asString();

	// 先查找redis中email对应的验证码是否合理
	std::string  verify_code;
	bool b_get_varify = RedisManager::getInstance()->get(CODEPREFIX + src_root["email"].asString(), verify_code);
	if (!b_get_varify) {
		std::cout << " get verify code expired" << std::endl;
		root["error"] = ErrorCodes::VerifyExpired;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	if (verify_code != src_root["verifycode"].asString()) {
		std::cout << " verify code error" << std::endl;
		root["error"] = ErrorCodes::VerifyCodeErr;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}
	// 查询数据库判断用户名和邮箱是否匹配
	bool email_valid = MysqlManager::getInstance()->checkEmail(name, email);
	if (!email_valid) {
		std::cout << " user email not match" << std::endl;
		root["error"] = ErrorCodes::EmailNotMatch;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	//更新密码为最新密码
	bool b_up = MysqlManager::getInstance()->updatePwd(name, pwd);
	if (!b_up) {
		std::cout << " update pwd failed" << std::endl;
		root["error"] = ErrorCodes::PasswdUpFailed;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	std::cout << "succeed to update password : " << pwd << std::endl;
	root["error"] = 0;
	root["email"] = email;
	root["user"] = name;
	root["passwd"] = pwd;
	root["verifycode"] = src_root["verifycode"].asString();
	std::string jsonstr = root.toStyledString();
	boost::beast::ostream(connection->m_response.body()) << jsonstr;
}

// 处理用户登录
void LogicSystem::handleUserLogin(std::shared_ptr<HttpConnection> connection)
{
	auto body_str = boost::beast::buffers_to_string(connection->m_request.body().data());
	std::cout << "receive body is " << body_str << std::endl;
	connection->m_response.set(boost::beast::http::field::content_type, "text/json");
	Json::Value root;
	Json::Reader reader;
	Json::Value src_root;
	bool parse_success = reader.parse(body_str, src_root);
	if (!parse_success) {
		std::cout << "Failed to parse JSON data!" << std::endl;
		root["error"] = ErrorCodes::Error_Json;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	auto email = src_root["email"].asString();
	auto pwd = src_root["passwd"].asString();
	std::cout << "login::email = " << email << std::endl;
	std::cout << "login::pwd = " << pwd << std::endl;

	UserInfo userInfo;
	// 查询Mysql数据库判断邮箱和密码是否匹配
	bool pwd_valid = MysqlManager::getInstance()->checkPwd(email, pwd, userInfo);
	if (!pwd_valid) {
		std::cout << "user pwd not match" << std::endl;
		root["error"] = ErrorCodes::PasswdInvalid;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	// 查询StatusServer找到合适的连接
	auto reply = StatusGrpcClient::getInstance()->getChatServer(userInfo.uid);
	if (reply.error()) {
		std::cout << " grpc get chat server failed, error is " << reply.error() << std::endl;
		root["error"] = ErrorCodes::RPCFailed;
		std::string jsonstr = root.toStyledString();
		boost::beast::ostream(connection->m_response.body()) << jsonstr;
		return ;
	}

	std::cout << "succeed to load userinfo uid is " << userInfo.uid << std::endl;
	root["error"] = 0;
	root["email"] = email;
	root["uid"] = userInfo.uid;
	root["token"] = reply.token();
	root["host"] = reply.host();
	root["port"] = reply.port();
	std::string jsonstr = root.toStyledString();
	boost::beast::ostream(connection->m_response.body()) << jsonstr;
}

LogicSystem::LogicSystem()
{
	// 注册get请求
	registerGet("/getTest", std::bind(&LogicSystem::handleGetTest, this, std::placeholders::_1));

	registerPost("/get_verifycode", std::bind(&LogicSystem::handlePostVerifyCode, this, std::placeholders::_1));

	registerPost("/user_register", std::bind(&LogicSystem::handleUserRegister, this, std::placeholders::_1));

	registerPost("/reset_pwd", std::bind(&LogicSystem::handleResetPwd, this, std::placeholders::_1));

	registerPost("/user_login", std::bind(&LogicSystem::handleUserLogin, this, std::placeholders::_1));
}
